package top.infopub.mgr.fia.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.infopub.dto.fia.FundsPlanDetailDto;
import top.infopub.dto.fia.FundsPlanDto;
import top.infopub.enums.fia.BondOutTypeEnum;
import top.infopub.enums.fia.FiaProcessDetailTypeEnum;
import top.infopub.enums.fia.FundsPlanCostTypeEnum;
import top.infopub.enums.mkt.ProProcesssStatusEnum;
import top.infopub.generic.GenericDao;
import top.infopub.generic.GenericServiceImpl;
import top.infopub.mgr.common.vo.RspVo;
import top.infopub.mgr.fia.dao.CommonDao;
import top.infopub.mgr.fia.dao.FundsPlanDao;
import top.infopub.mgr.fia.dao.FundsPlanDetailDao;
import top.infopub.mgr.fia.domain.FundsPlanSummaryDomain;
import top.infopub.mgr.fia.jsonvo.FundsPlanJsonVo;
import top.infopub.mgr.fia.service.FiaProcessManageService;
import top.infopub.mgr.fia.service.FundsPlanService;
import top.infopub.mgr.fia.vo.FundsPlanSummaryVo;
import top.infopub.mgr.flow.service.OAFlowService;
import top.infopub.mgr.hr.dao.OrgInfoDao;
import top.infopub.mgr.hr.dao.StaffInfoDao;
import top.infopub.model.common.HrOrgInfo;
import top.infopub.model.common.ProInfo;
import top.infopub.model.fia.FundsPlan;
import top.infopub.model.fia.FundsPlanCost;
import top.infopub.model.fia.FundsPlanDetail;
import top.infopub.model.fia.FundsPlanTypes;
import top.infopub.model.hr.OrgInfo;
import top.infopub.model.hr.StaffInfo;
import top.infopub.security.util.SessionUserUtils;
import top.infopub.security.vo.AuthorizationVO;
import top.infopub.tdp.sys.service.CodeGeneratorConfigService;
import top.infopub.util.DateUtil;

import java.util.*;

@Service
public class FundsPlanServiceImpl extends GenericServiceImpl<FundsPlan, String> implements
		FundsPlanService {
	@Autowired
	private FundsPlanDao fundsPlanDao;

	@Autowired
	private FundsPlanDetailDao fundsPlanDetailDao;

	@Autowired
	private CommonDao commonDao;

	@Autowired
	private StaffInfoDao staffInfoDao;

	@Autowired
	private OrgInfoDao orgInfoDao;

	@Autowired
	private CodeGeneratorConfigService codeGeneratorConfigService;

	@Autowired
	private OAFlowService oaFlowService;

	@Autowired
	private FiaProcessManageService fiaProcessManageService;
	
	@Override
	public GenericDao<FundsPlan, String> getDao() {
		return fundsPlanDao;
	}

    @Override
    public Page<FundsPlanSummaryDomain> selectPageByDomainWhere(Page<FundsPlanSummaryDomain> page,
																FundsPlanSummaryVo fundsPlanSummaryVo) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        return (Page<FundsPlanSummaryDomain>)fundsPlanDao.selectByDomainWhere(fundsPlanSummaryVo);
    }

	@Override
	public FundsPlanJsonVo queryDetailById(String id) {
		FundsPlanJsonVo fundsPlanJson = new FundsPlanJsonVo();
		if (StringUtils.isNotBlank(id)) {
			//基础信息
			FundsPlanDto fundsPlanDto = fundsPlanDao.queryDetailById(id);
			fundsPlanJson.setInfo(fundsPlanDto);

			//详情列表
			List<FundsPlanDetailDto> detailList = getFundsPlanDetailList(id, fundsPlanDto.getProCode(), fundsPlanDto.getBelongDate());
			fundsPlanJson.setDetailList(detailList);
		} else {
			//基础信息
			FundsPlanDto fundsPlanDto = new FundsPlanDto();
			fundsPlanDto.setCodes(codeGeneratorConfigService.generatorCode("FIA_FUNDS_PLAN"));
			AuthorizationVO vo = SessionUserUtils.getSessionAttributeForUserDtl();
			StaffInfo staffInfo = staffInfoDao.selectByPrimaryKey(vo.getHrStaffId());
			fundsPlanDto.setCompName("");
			if (staffInfo != null) {
				OrgInfo orgInfo = orgInfoDao.selectByPrimaryKey(staffInfo.getPkOrg());
				if (orgInfo != null) {
					fundsPlanDto.setSgOrgId(orgInfo.getId());
					fundsPlanDto.setCompName(orgInfo.getCompName());
				}
			}
			fundsPlanJson.setInfo(fundsPlanDto);

			//项目信息列表
			List<ProInfo> proInfoList = commonDao.queryCapSetupProList(ProProcesssStatusEnum.PRO_STATUS9.getCode());
			fundsPlanJson.setProInfoList(proInfoList);
		}
		//组织架构和合作单位列表
		List<HrOrgInfo> orgInfoList = commonDao.queryAllOrgCoopList();
		fundsPlanJson.setOrgInfoList(orgInfoList);
		return fundsPlanJson;
	}

	@Override
	public FundsPlanJsonVo queryDetail(String proCode, String belongDate) {
		FundsPlanJsonVo fundsPlanJson = new FundsPlanJsonVo();
		FundsPlan fundsPlan = fundsPlanDao.queryByProCodeAndBelongDate(proCode, belongDate);
		String id = null;
		if (fundsPlan != null) {
			//基础信息
			FundsPlanDto fundsPlanDto = fundsPlanDao.queryDetailById(fundsPlan.getId());
			fundsPlanJson.setInfo(fundsPlanDto);
			id = fundsPlan.getId();
		}
		//详情列表
		List<FundsPlanDetailDto> detailList = getFundsPlanDetailList(id, proCode, belongDate);
		fundsPlanJson.setDetailList(detailList);
		return fundsPlanJson;
	}

	@Override
	public List<FundsPlanDetailDto> queryTypeByParentId(String typeId, String belongDate) {
//		String nextMonth = null;
//		String lowestMonth = null;
//		if (StringUtils.isNotBlank(belongDate)) {
//			Calendar now = Calendar.getInstance();
//			now.setTime(DateUtil.string2UtilDate(belongDate, DateUtil.DATE_STYLE_YYYY_MM));
//			now.add(Calendar.MONTH, 1);
//			nextMonth = DateUtil.utilDate2String(now.getTime(), DateUtil.DATE_STYLE_YYYY_MM);
//			now.add(Calendar.MONTH, 1);
//			lowestMonth = DateUtil.utilDate2String(now.getTime(), DateUtil.DATE_STYLE_YYYY_MM);
//		}
		FundsPlanTypes fpt = fundsPlanDetailDao.queryTypesByTypeId(typeId);
		List<FundsPlanTypes> lowestList = fundsPlanDetailDao.queryTypesByParentId(fpt.getId());
		if (lowestList == null || lowestList.size() <= 0) return null;
		List<FundsPlanDetailDto> result = new ArrayList<>();
		FundsPlanDetailDto fpd;
		for (FundsPlanTypes tmpFpt : lowestList) {
			fpd = new FundsPlanDetailDto();
			fpd.setTypeId(tmpFpt.getTypeId());
			fpd.setTypeName(tmpFpt.getTypeName());
			fpd.setTypes("3");
//			fpd.setNextMonth(nextMonth);
//			fpd.setLowestMonth(lowestMonth);
			fpd.setIsList(tmpFpt.getIsList());
			fpd.setIsAdd("0");
			if (StringUtils.equals("1", tmpFpt.getIsList())) {
				List<Map<String, String>> bondOutTypeList = BondOutTypeEnum.asList();
				fpd.setBondOutTypeList(bondOutTypeList);
			}
			result.add(fpd);
		}
		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public RspVo edit(FundsPlanJsonVo fundsPlanJson, Integer submitType, AuthorizationVO vo) {
		FundsPlan tmpFp = new FundsPlan();
		FundsPlan fundsPlan = new FundsPlan();
		FundsPlanDto fundsPlanDto = fundsPlanJson.getInfo();
		BeanUtils.copyProperties(fundsPlanDto, fundsPlan);
		fundsPlan.setUptBy(vo.getId());
		fundsPlan.setUptTime(new Date());
		String[] belongArrs = fundsPlanDto.getBelongDate().split("-");
		fundsPlan.setBelongYear(belongArrs[0]);
		fundsPlan.setBelongMonth(belongArrs[1]);
		if (StringUtils.isNotBlank(fundsPlanDto.getId())) {
			//校验资金上交数据是否存在
			tmpFp = fundsPlanDao.selectByPrimaryKey(fundsPlanDto.getId());
			if (tmpFp == null) return RspVo.getFailureResponse(400, "月度资金计划数据不存在");
			//判断审批状态
			if (StringUtils.isNotBlank(tmpFp.getProcessStatus())
					&& (StringUtils.equals(ProProcesssStatusEnum.PRO_STATUS1.getCode(), tmpFp.getProcessStatus())
					|| StringUtils.equals(ProProcesssStatusEnum.PRO_STATUS9.getCode(), tmpFp.getProcessStatus()))) {
				return RspVo.getFailureResponse(400, "审批状态不正确，操作失败");
			}
			fundsPlanDao.updateByIdSelective(fundsPlan);
		} else {
			fundsPlan.setAddBy(vo.getId());
			fundsPlan.setAddTime(new Date());
			fundsPlanDao.insertSelective(fundsPlan);
		}

		//保存详情信息
		List<FundsPlanDetailDto> detailList = fundsPlanJson.getDetailList();
		if (detailList != null && detailList.size() > 0) {
			int sortNo = 1;
			for (FundsPlanDetailDto fpdd : detailList) {
				//详情信息
				if (fpdd == null || !StringUtils.equals(fpdd.getTypes(), "3")) continue;
				FundsPlanDetail fpd = new FundsPlanDetail();
				BeanUtils.copyProperties(fpdd, fpd);
				fpd.setUptBy(vo.getId());
				fpd.setUptTime(new Date());
				fpd.setSortNo(sortNo);
				fpd.setFundsPlanId(fundsPlan.getId());
				//保存或更新详情信息
				if (StringUtils.isNotBlank(fpd.getId())) {
					fundsPlanDetailDao.updateByIdSelective(fpd);
				} else {
					fpd.setAddBy(vo.getId());
					fpd.setAddTime(new Date());
					fundsPlanDetailDao.insert(fpd);
				}
				//如果类型是费用枚举类对应的类型，需要处理费用列表
				if (FundsPlanCostTypeEnum.getByTypeId(fpdd.getTypeId()) != null) {
					//先删除，包装页面删除数据后保存后，重新查询不会显示以前的数据
					fundsPlanDetailDao.deleteFundsPlanCostByDetailId(fpd.getId());
					//设置一些必须的值并批量保存费用信息
					if (fpdd.getCostList() != null && fpdd.getCostList().size() > 0) {
						for (FundsPlanCost cost : fpdd.getCostList()) {
							cost.setFpDetailId(fpd.getId());
							cost.setCostType(FundsPlanCostTypeEnum.getByTypeId(fpdd.getTypeId()).getCode());
							cost.setAddBy(vo.getId());
							cost.setAddTime(new Date());
						}
						fundsPlanDetailDao.insertFundsPlanCostBatch(fpdd.getCostList());
					}
				}
				sortNo++;
			}
		}

		if (submitType == 1) {
			if (StringUtils.isNotBlank(tmpFp.getOaId())) {
				oaFlowService.finishOA(tmpFp.getOaId());
			}
			FundsPlanJsonVo tmpJson = queryDetailById(fundsPlan.getId());
			tmpJson.setOrgInfoList(null);
			tmpJson.setProInfoList(null);
			String detailJson = JSON.toJSONString(tmpJson);
			fiaProcessManageService.sendProcess(FiaProcessDetailTypeEnum.PRO_NODE_TYPE2, detailJson, fundsPlan.getId(), fundsPlan.getProCode(), vo);
		}
		return RspVo.getSuccessResponse();
	}

	/**
	 * 分类详情整合
	 * @param fundsPlanId
	 * @param proCode
	 * @param currDate
	 * @return
	 */
	private List<FundsPlanDetailDto> getFundsPlanDetailList(String fundsPlanId, String proCode, String currDate) {
		//查询明细list
		List<FundsPlanDetailDto> detailList = null;
		if (StringUtils.isNotBlank(fundsPlanId)) {
			detailList = fundsPlanDetailDao.queryCurrDetailByFundsPlanId(fundsPlanId);
		} else {
			detailList = fundsPlanDetailDao.queryNextDetailByProCodeAndCurrDate(proCode, currDate);
			if (detailList == null || detailList.size() <= 0) {
				detailList = fundsPlanDetailDao.queryLowestDetailByProCodeAndCurrDate(proCode, currDate);
			}
		}
		String nextMonth = null;
		String lowestMonth = null;
		if (StringUtils.isNotBlank(currDate)) {
			Calendar now = Calendar.getInstance();
			now.setTime(DateUtil.string2UtilDate(currDate, DateUtil.DATE_STYLE_YYYY_MM));
			now.add(Calendar.MONTH, 1);
			nextMonth = DateUtil.utilDate2String(now.getTime(), DateUtil.DATE_STYLE_YYYY_MM);
			now.add(Calendar.MONTH, 1);
			lowestMonth = DateUtil.utilDate2String(now.getTime(), DateUtil.DATE_STYLE_YYYY_MM);
		}
		List<FundsPlanTypes> typesList = fundsPlanDetailDao.queryTypesByParentId("0");
		if (typesList != null && typesList.size() > 0) {
			List<FundsPlanDetailDto> result = new ArrayList<>();
			FundsPlanDetailDto detail;
			for (FundsPlanTypes fpt : typesList) {
				if (fpt == null) continue;
				detail = setTypesInfo(fpt, "1");
				result.add(detail);
				List<FundsPlanTypes> nextList = fundsPlanDetailDao.queryTypesByParentId(fpt.getId());
				if (nextList != null && nextList.size() > 0) {
					for (FundsPlanTypes chrenFpt : nextList) {
						if (chrenFpt == null) continue;
						detail = setTypesInfo(chrenFpt, "2");
						result.add(detail);
						List<FundsPlanTypes> lowestList = fundsPlanDetailDao.queryTypesByParentId(chrenFpt.getId());
						if (lowestList == null || lowestList.size() <= 0) continue;
//						List<FundsPlanDetailDto> list = new ArrayList<>();
						//如果详情存在，需要用该List重新复制一遍第三级节点的类型列表，因为第三级节点列表可以新增，所以在详情里面同类型可能出现多个
						if (detailList == null || detailList.size() <= 0) {
							FundsPlanDetailDto fpd;
							for (FundsPlanTypes tmpFpt : lowestList) {
								fpd = new FundsPlanDetailDto();
								fpd.setTypeId(tmpFpt.getTypeId());
								fpd.setTypeName(tmpFpt.getTypeName());
								fpd.setTypes("3");
								fpd.setIsList(tmpFpt.getIsList());
								fpd.setIsAdd("0");
								if (StringUtils.equals("1", tmpFpt.getIsList())) {
									List<Map<String, String>> bondOutTypeList = BondOutTypeEnum.asList();
									fpd.setBondOutTypeList(bondOutTypeList);
								}
								fpd.setNextMonth(nextMonth);
								fpd.setLowestMonth(lowestMonth);
								result.add(fpd);
							}
						} else {
							//以查询到的详情为主，因为详情里面可能存在新增的重复类型
							for (FundsPlanDetailDto fpd : detailList) {
								for (FundsPlanTypes tmpFpt : lowestList) {
									if (StringUtils.equals(fpd.getTypeId(), tmpFpt.getTypeId())) {
										if (StringUtils.isBlank(fpd.getCurrDate()) || fpd.getCurrDate().length() < 8) {
											fpd.setCurrDate(null);
											fpd.setFundsPlanId(null);
										}
										if (StringUtils.isBlank(fpd.getNextMonth())) fpd.setNextMonth(nextMonth);
										if (StringUtils.isBlank(fpd.getLowestMonth())) fpd.setLowestMonth(lowestMonth);
										if (StringUtils.equals("1", tmpFpt.getIsList())) {
											List<Map<String, String>> bondOutTypeList = BondOutTypeEnum.asList();
											fpd.setBondOutTypeList(bondOutTypeList);
										}
										if (StringUtils.isNotBlank(fpd.getId()) && FundsPlanCostTypeEnum.getByTypeId(fpd.getTypeId()) != null) {
											List<FundsPlanCost> costList = fundsPlanDetailDao.queryCostList(fpd.getId());
											fpd.setCostList(costList);
										}
										fpd.setIsList(tmpFpt.getIsList());
										fpd.setTypes("3");
										if (StringUtils.equals("1", fpd.getIsAdd())) {
											List<FundsPlanDetailDto> subAddList = new ArrayList<>();
											FundsPlanDetailDto tmpFpd;
											for (FundsPlanTypes tmp : lowestList) {
												tmpFpd = new FundsPlanDetailDto();
												tmpFpd.setTypeId(tmp.getTypeId());
												tmpFpd.setTypeName(tmp.getTypeName());
												tmpFpd.setTypes("3");
												tmpFpd.setIsList(tmp.getIsList());
												tmpFpd.setIsAdd("0");
												if (StringUtils.equals("1", tmp.getIsList())) {
													List<Map<String, String>> bondOutTypeList = BondOutTypeEnum.asList();
													tmpFpd.setBondOutTypeList(bondOutTypeList);
												}
												if (StringUtils.equals(fpd.getTypeId(), tmp.getTypeId())) {
													tmpFpd.setCurrDate(fpd.getCurrDate());
													tmpFpd.setCurrAmt(fpd.getCurrAmt());
												}
												subAddList.add(tmpFpd);
											}
											fpd.setSubAddList(subAddList);
										}
										result.add(fpd);
										break;
									}
								}
							}
						}
					}
				}
			}
			return result;
		}
		return null;
	}

	private FundsPlanDetailDto setTypesInfo(FundsPlanTypes fpt, String types) {
		FundsPlanDetailDto detail = new FundsPlanDetailDto();
		detail.setTypeId(fpt.getTypeId());
		detail.setTypeName(fpt.getTypeName());
		detail.setTypes(types);
		return detail;
	}
}